#pragma once

#include <iostream>
#include <string>
#include <memory>
#include <sys/select.h>
#include "Socket.hpp"
#include "Logger.hpp"
#include "InetAddr.hpp"

const static int gsize = sizeof(fd_set) * 8;
const static int gdefault = -1;

class SelectServer
{
public:
    SelectServer(uint16_t port)
        : _listensock(std::make_unique<TcpSocket>(port))
    {
        // 建立listen套接字
        _listensock->BuildListenSocketMethod(port);
        // 初始化数组
        for (int i = 0; i < gsize; i++)
        {
            array[i] = gdefault;
        }
        array[0] = _listensock->Sockfd();
    }
    void Accepter()
    {
        InetAddr clientaddr;
        int sockfd = _listensock->AcceptSocketOrDie(&clientaddr);
        if (sockfd > 0)
        {
            // 这里不能直接recv，而是要连接的套接字托管给select
            // 我们在创建的数组中标记出连接的sockfd对应的数组下标位置
            int pos = 0;
            for (; pos < gsize; pos++)
            {
                if (array[pos] = gdefault)
                {
                    array[pos] = sockfd;
                    break;
                }
            }
            // 这里说明服务器满了
            if (pos == gsize)
            {
                LOG(LogLevel::WARNING) << "server is full!";
                close(sockfd);
            }
        }
    }
    void Recver(int index)
    {
        int sockfd = array[index];
        char buffer[1024];
        ssize_t n = recv(sockfd, buffer, sizeof(buffer), 0);
        if (n > 0)
        {
            buffer[n] = 0;
            std::cout << "client say@ " << buffer << std::endl;
            std::string echo_string = "server echo# ";
            echo_string += buffer;
            send(sockfd, echo_string.c_str(), echo_string.size(), 0);
        }
        else if (n == 0)
        {
            LOG(LogLevel::INFO) << "client quit, me too: " << array[index];
            array[index] = gdefault;
            close(sockfd);
        }
        else
        {
            LOG(LogLevel::WARNING) << "recv error: " << array[index];
            array[index] = gdefault;
            close(sockfd);
        }
    }
    void EventDispatcher(fd_set &rfds)
    {
        // 这里一定是有新的事件到来
        LOG(LogLevel::INFO) << "have new work.....";
        for (int i = 0; i < gsize; i++)
        {
            if (array[i] == gdefault)
                continue;
            if (FD_ISSET(array[i], &rfds))
            {
                if (array[i] == _listensock->Sockfd())
                {
                    // 连接管理
                    Accepter();
                }
                else
                {
                    // 读事件处理器
                    Recver(i);
                }
            }
        }
    }

    void Run()
    {
        while (true)
        {
            struct timeval timeout = {0, 0};
            fd_set rfds;
            FD_ZERO(&rfds); // 清空
            int maxfd = gdefault;
            for (int i = 0; i < gsize; i++)
            {
                if (array[i] == gdefault)
                    continue;
                // 到这里就是有新的fd
                FD_SET(array[i], &rfds);
                if (maxfd < array[i])
                    maxfd = array[i];
                LOG(LogLevel::INFO) << "add fd: " << array[i];
            }
            int n = select(maxfd + 1, &rfds, nullptr, nullptr, nullptr);
            if (n == 0)
            {
                LOG(LogLevel::INFO) << "time......";
                break;
            }
            else if (n < 0)
            {
                LOG(LogLevel::WARNING) << "select error!";
                break;
            }
            else
            {
                EventDispatcher(rfds);
            }
        }
    }
    ~SelectServer()
    {
    }

private:
    std::unique_ptr<Socket> _listensock;
    int array[gsize];
};